package de.lmu.mvs.lerngruppenfinder;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;

import org.joda.time.DateTime;

import be.billington.calendar.recurrencepicker.EventRecurrence;
import be.billington.calendar.recurrencepicker.EventRecurrenceFormatter;
import be.billington.calendar.recurrencepicker.RecurrencePickerDialog;

import com.beardedhen.androidbootstrap.BootstrapEditText;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
import com.fourmob.datetimepicker.date.DatePickerDialog;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.ical.compat.javautil.DateIteratorFactory;
import com.sleepbot.datetimepicker.time.RadialPickerLayout;
import com.sleepbot.datetimepicker.time.TimePickerDialog;

import de.lmu.mvs.lerngruppenfinder.interests.InterestNode;
import de.lmu.mvs.lerngruppenfinder.interests.InterestTree;
import de.lmu.mvs.lerngruppenfinder.utils.ApplicationController;
import de.lmu.mvs.lerngruppenfinder.utils.BaseActivity;
import de.lmu.mvs.lerngruppenfinder.utils.Constants;
import de.lmu.mvs.lerngruppenfinder.utils.FileApi;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerConnectorListener;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerError;
import de.lmu.mvs.lerngruppenfinder.widget.ExpandablePanel;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.TransitionDrawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.format.Time;
import android.util.Log;
import android.util.EventLogTags.Description;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class AddGroupActivity extends FragmentActivity {

	private static final String TAG = AddGroupActivity.class.getSimpleName();
	private static final String DATEPICKER_TAG = "datepicker";
	private static final String TIMEPICKER_TAG = "timepicker";

	private BootstrapEditText dateEdit;
	private BootstrapEditText startTimeEdit;
	private BootstrapEditText endTimeEdit;

	int selectedhour, selectedminute, selectedmonth, selectedyear, selectedday;
	int endtimeHour, endtimeMinute;
	int fachgebiet, building;
	String recrule;
	LatLng ltg;
	Time time;

	boolean repeated, dateset, starttimeset, endtimeset, locationset, interestsSet;
	ArrayList<String> repeatids;
	ArrayList<String> endlist;
	ArrayList<String> beginlist;

	private String recurrenceRule;
	final int PICK_POSITION = 2345;

	private LinearLayout mUserInteractionView;
	private LinearLayout mInterestView;
	private InterestTree mInterestTree;
	private InterestTree mEventTree;

	private boolean mTransitionStateSave = false;

	/**
	 * map keeps separate interest arrays for each created view.
	 * Is used to determine which interests have changed after an edit.
	 */
	HashMap<Integer, List<Integer>> mUserInterestsMap = new HashMap<Integer, List<Integer>>();

	/** all interests that the user has */
	private List<Integer> mUserInterests = new ArrayList<Integer>();

	private GoogleMap mMap;

	private Location lastLocation;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
		getActionBar().hide();
		setContentView(R.layout.activity_add_group);

		mMap = ((SupportMapFragment) getSupportFragmentManager()
				.findFragmentById(R.id.map)).getMap();

		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		lastLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);

		if(mMap != null){
			mMap.getUiSettings().setCompassEnabled(false);
			mMap.getUiSettings().setZoomControlsEnabled(false);
			mMap.getUiSettings().setMyLocationButtonEnabled(false);
			mMap.getUiSettings().setAllGesturesEnabled(false);
			mMap.setMyLocationEnabled(true);
			mMap.setOnMapClickListener(new OnMapClickListener() {

				@Override
				public void onMapClick(LatLng arg0) {
					startPosSelectActivity(null);
				}
			});

			if(lastLocation != null){
				CameraPosition cameraPosition = new CameraPosition.Builder()
				.target(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()))   
				.zoom(Constants.DETAIL_MAP_ZOOM).tilt(Constants.MAP_CAMERA_TILT).build();
				mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

				ltg = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());

				mMap.addMarker(
						new MarkerOptions()
						.position(new LatLng(ltg.latitude, ltg.latitude)));
				locationset = true;
			} else {
				locationset = false;
			}
		}

		// set font family for user interaction bar
		((TextView)findViewById(R.id.user_interaction_save_changes))
		.setTypeface(ApplicationController.getTypeFace());
		((TextView)findViewById(R.id.user_interaction_cancel))
		.setTypeface(ApplicationController.getTypeFace());
		((TextView)findViewById(R.id.interest_edit))
		.setTypeface(ApplicationController.getTypeFace());

		// set user interaction listener for save
		findViewById(R.id.user_interaction_save_changes).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				gruppeErstellen(null);
			}
		});

		// set user interaction listener for cancel
		findViewById(R.id.user_interaction_back).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				onBackPressed();
			}
		});

		findViewById(R.id.user_interaction_cancel).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				onBackPressed();
			}
		});

		dateEdit = (BootstrapEditText) findViewById(R.id.dateEdit);
		startTimeEdit = (BootstrapEditText) findViewById(R.id.startTimeEdit);
		endTimeEdit = (BootstrapEditText) findViewById(R.id.endTimeEdit);
		dateEdit.setInputType(InputType.TYPE_NULL);
		startTimeEdit.setInputType(InputType.TYPE_NULL);
		endTimeEdit.setInputType(InputType.TYPE_NULL);
		dateset = false;
		starttimeset = false;
		endtimeset = false;
		interestsSet = false;
		repeated = false;

		final Calendar calendar = Calendar.getInstance();
		time = new Time();
		setupInterests();

		DatePickerDialog.OnDateSetListener odsl = getDateListener();
		// listener for starttime
		TimePickerDialog.OnTimeSetListener otsl = new TimePickerDialog.OnTimeSetListener() {

			@Override
			public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
				selectedhour = hourOfDay;
				selectedminute = minute;
				String hours = (hourOfDay < 10) ? "0" + hourOfDay : hourOfDay + "";
				String minutes = (minute < 10) ? "0" + minute : minute + "";

				startTimeEdit.setText( hours + ":" + minutes + "");
				starttimeset = true;

				checkInputFromUser();
			}
		};
		// listener for endtime
		TimePickerDialog.OnTimeSetListener oetsl = new TimePickerDialog.OnTimeSetListener() {

			@Override
			public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {
				endtimeHour = hourOfDay;
				endtimeMinute = minute;
				String hours = (hourOfDay < 10) ? "0" + hourOfDay : hourOfDay + "";
				String minutes = (minute < 10) ? "0" + minute : minute + "";

				endTimeEdit.setText( hours + ":" + minutes + "");
				endtimeset = true;

				checkInputFromUser();
			}
		};

		final DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(odsl, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), false);

		DateTime now = DateTime.now();
		final TimePickerDialog startTimePickerDialog = TimePickerDialog.newInstance(otsl, now.getHourOfDay() ,now.getMinuteOfHour(), true, false);
		now.plusHours(1);
		final TimePickerDialog endTimePickerDialog = TimePickerDialog.newInstance(oetsl, now.getHourOfDay() ,now.getMinuteOfHour(), true, false);

		dateEdit.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				datePickerDialog.setYearRange(calendar.get(Calendar.YEAR), 2020);
				datePickerDialog.show(getSupportFragmentManager(), DATEPICKER_TAG);
			}
		});
		startTimeEdit.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				startTimePickerDialog.show(getSupportFragmentManager(), TIMEPICKER_TAG);
			}
		});
		endTimeEdit.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				endTimePickerDialog.show(getSupportFragmentManager(), TIMEPICKER_TAG);
			}
		});

		if (savedInstanceState != null) {
			DatePickerDialog dpd = (DatePickerDialog) getSupportFragmentManager().findFragmentByTag(DATEPICKER_TAG);
			if (dpd != null) {
				dpd.setOnDateSetListener(odsl);
			}

			TimePickerDialog tpd = (TimePickerDialog) getSupportFragmentManager().findFragmentByTag(TIMEPICKER_TAG);
			if (tpd != null) {
				tpd.setOnTimeSetListener(otsl);
			}
		}        
/*
		CheckBox ckb = (CheckBox) findViewById(R.id.checkbox);        
		ckb.setOnCheckedChangeListener(new OnCheckedChangeListener(){
			@Override
			public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
				final TextView wdh = (TextView) findViewById(R.id.wdhtext);
				if (!arg1)
				{
					repeated = false;
					wdh.setText(getString(R.string.recurrence_string));
				}
				else
				{
					repeated=true;
					RecurrencePickerDialog recurrencePickerDialog = new RecurrencePickerDialog();
					if (recurrenceRule != null && recurrenceRule.length() > 0) {
						Bundle bundle = new Bundle();
						bundle.putString(RecurrencePickerDialog.BUNDLE_RRULE, recurrenceRule);
						recurrencePickerDialog.setArguments(bundle);
					}				    
					recurrencePickerDialog.setOnRecurrenceSetListener(new RecurrencePickerDialog.OnRecurrenceSetListener() {
						@Override
						public void onRecurrenceSet(String rrule) {
							recurrenceRule = rrule;
							if (recurrenceRule != null && recurrenceRule.length() > 0) {
								EventRecurrence recurrenceEvent = new EventRecurrence();
								recurrenceEvent.setStartDate(time);
								recurrenceEvent.parse(rrule);
								recrule = rrule;
								String srt = EventRecurrenceFormatter.getRepeatString(AddGroupActivity.this, getResources(), recurrenceEvent, true);
								wdh.setText(srt);
								Log.i("RECURRENCE", recrule);
							} else {
								Log.i("RECURRENCE", "No recurrence");
							}
						}
					});
					recurrencePickerDialog.show(getSupportFragmentManager(), "recurrencePicker");
				}

				checkInputFromUser();
			}});*/

		// set textchanged listener for the edittext fields

		TextWatcher textWatcher = new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) { }

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) { }

			@Override
			public void afterTextChanged(Editable s) {
				// just listen for changed text and check input
				checkInputFromUser();
			}
		};
		((BootstrapEditText)findViewById(R.id.vName)).addTextChangedListener(textWatcher);
		((BootstrapEditText)findViewById(R.id.descText)).addTextChangedListener(textWatcher);

		initTimeViews();
	}

	@Override
	public void onActivityResult(int requestCode,int resultCode, Intent data)
	{
		super.onActivityResult(requestCode, resultCode, data);

		if (requestCode == PICK_POSITION) {
			// Make sure the request was successful
			if (resultCode == RESULT_OK) {

				ltg = (LatLng) data.getExtras().get("Gpscoords");

				if(ltg != null){
					CameraPosition cameraPosition = new CameraPosition.Builder()
					.target(ltg)   
					.zoom(Constants.DETAIL_MAP_ZOOM).tilt(Constants.MAP_CAMERA_TILT).build();
					mMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

					mMap.addMarker(
							new MarkerOptions()
							.position(ltg));
				}
			}
		}

		if (requestCode == SetInterestActivity.REQUEST_INTEREST) {
			if (resultCode == RESULT_OK) {
				if(data != null){
					Log.d(TAG, data.getStringExtra(SetInterestActivity.INTEREST_RESULT));

					String interestResult = data.getStringExtra(SetInterestActivity.INTEREST_RESULT).trim();
					int interestEditId = data.getIntExtra(SetInterestActivity.INTERESTS_EDIT_ID, 0);
					if(interestResult != null){

						// create new list with edited userinterests and store in interestmap
						mUserInterests = new ArrayList<Integer>(interestResult.split(";").length);
						for (int i = 0; i < interestResult.split(";").length; i++) {
							try {
								mUserInterests.add(Integer.parseInt(interestResult.split(";")[i]));
							} catch(NumberFormatException e){
								Log.d(TAG, "Skipped interest id "+interestResult.split(";")[i]+" when converting string result "+interestResult);
							}
						}
						if (mUserInterests.size() > 0){
							fachgebiet = mUserInterests.get(0);
							interestsSet = true;
						} else {
							interestsSet = false;
						}
						createInterestViews();
					}
				}
			}
		}

		checkInputFromUser();
	}

	private DatePickerDialog.OnDateSetListener getDateListener()
	{
		return new DatePickerDialog.OnDateSetListener() {

			@Override
			public void onDateSet(DatePickerDialog datePickerDialog, int year, int month, int day) {
				selectedmonth = month;
				selectedyear = year;
				selectedday = day;				
				int actualmonth = month + 1;				
				dateEdit.setText(day+"."+actualmonth+"."+year);
				time.set(day, month, year);
				dateset = true;

				checkInputFromUser();
			}
		};
	};

	// FIXME make unique for each time
	private TimePickerDialog.OnTimeSetListener getTimeListener()
	{
		return new TimePickerDialog.OnTimeSetListener() {

			@Override
			public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) {

				selectedhour = hourOfDay;
				selectedminute = minute;
				String hours = (hourOfDay < 10) ? "0" + hourOfDay : hourOfDay + "";
				String minutes = (minute < 10) ? "0" + minute : minute + "";

				startTimeEdit.setText( hours + ":" + minutes + "");
				starttimeset = true;
			}
		};
	}

	private void initTimeViews(){
		DateTime dateTime = DateTime.now();

		// date
		selectedmonth = dateTime.getMonthOfYear();
		selectedyear = dateTime.getYear();
		selectedday = dateTime.getDayOfMonth();		
		dateEdit.setText(dateTime.getDayOfMonth()+"."+dateTime.getMonthOfYear()+"."+dateTime.getYear());
		time.set(dateTime.getDayOfMonth(), dateTime.getMonthOfYear(), dateTime.getYear());
		dateset = true;

		//starttime
		selectedhour = dateTime.getHourOfDay();
		selectedminute = dateTime.getMinuteOfHour();
		String hours = (selectedhour < 10) ? "0" + selectedhour : selectedhour + "";
		String minutes = (selectedminute < 10) ? "0" + selectedminute : selectedminute + "";

		startTimeEdit.setText( hours + ":" + minutes + "");
		starttimeset = true;

		// endtime
		dateTime.plusHours(1);
		endtimeHour = dateTime.getHourOfDay();
		endtimeMinute = dateTime.getMinuteOfHour();
		hours = (endtimeHour < 10) ? "0" + endtimeHour : endtimeHour + "";
		minutes = (endtimeMinute < 10) ? "0" + endtimeMinute : endtimeMinute + "";

		endTimeEdit.setText( hours + ":" + minutes + "");
		endtimeset = true;

		checkInputFromUser();
	}

	public void startPosSelectActivity(View view){
		startActivityForResult(new Intent(this, PositionSelectActivity.class), PICK_POSITION);
	}

	@SuppressLint("NewApi")
	public void gruppeErstellen(View view) {

		Context context = getApplicationContext();
		BootstrapEditText textview = (BootstrapEditText) findViewById(R.id.vName);
		String name = textview.getText().toString();

		BootstrapEditText desc = (BootstrapEditText) findViewById(R.id.descText);
		String description = desc.getText().toString();

		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar cal = Calendar.getInstance();

		time.set(0, selectedminute, selectedhour, selectedday, selectedmonth, selectedyear);
		String begindate = df.format(new Date(time.toMillis(true)));

		beginlist = new ArrayList<String>();
		endlist = new ArrayList<String>();

		if(name.isEmpty()) {
			CharSequence txt = "Bitte Name eingeben!";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if (fachgebiet == 0)
		{
			CharSequence txt = "Interesse ausw�hlen";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if(ltg == null) {
			CharSequence txt = "Bitte Ort ausw�hlen";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if (!dateset)
		{
			CharSequence txt = "Bitte Datum einstellen";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if (!starttimeset)
		{
			CharSequence txt = "Bitte Uhrzeit einstellen";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if (!endtimeset && (selectedhour > endtimeHour || (selectedhour == endtimeHour && selectedminute >= endtimeMinute)))
		{
			CharSequence txt = "Bitte Ende einstellen";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else if (description.isEmpty())	{
			CharSequence txt = "Bitte Beschreibung eingeben";
			Toast toast = Toast.makeText(context, txt, 	Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		else
		{
			time.set(0, endtimeMinute, endtimeHour, selectedday, selectedmonth, selectedyear);		
			String enddate = df.format( new Date(time.toMillis(true)));

			ServerConnector.createEvent(new ServerConnectorListener<JsonObject>() {
				@Override
				public void requestFinished(JsonObject json) {
					// TODO Auto-generated method stub
					Intent intent = new Intent(getBaseContext(), GroupDetailActivity.class);
					try {
						FileApi.writeJsonToStorage(json, "actualEvent", AddGroupActivity.this);
					} catch (IOException e) {
						Log.e(STORAGE_SERVICE, e.toString());
					}
					startActivity(intent);
					finish();
				}

				@Override
				public void requestError(ServerError error) {
				}
			}, name, description, fachgebiet, building, begindate, enddate ,ltg.latitude, ltg.longitude );
		}
		/*
		if (recrule != null && repeated == true )
		{

			int durationHour = endtimeHour - selectedhour;
			int durationMinute = endtimeMinute - selectedminute;

			Date date = new Date(time.toMillis(false));
			cal.setTime(date);
			try {
				for (Date d : DateIteratorFactory.createDateIterable("RRULE:" + recrule, date, TimeZone.getTimeZone("UTC"), true)) {	
					cal.setTime(d);	
					String sdate = df.format(cal.getTime());
					beginlist.add(sdate);
					cal.setTime(d);
					// FIXME this is probably wrong -> add minutes properly
					cal.add(Calendar.HOUR_OF_DAY, durationHour);
					cal.add(Calendar.HOUR_OF_DAY, durationMinute);
					String enddate = df.format(cal.getTime());
					endlist.add(enddate);					

					Log.i("BEGINDATE", sdate);
					Log.i("ENDATE", enddate);
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}		
		}

		if (beginlist.size() == endlist.size() && beginlist.size() > 0 && repeated == true )
		{
			Log.i("REPEATLOOP", "ENTER");
			// FIXME make minutes properly
			time.set(0, selectedminute, selectedhour+endtimeHour, selectedday, selectedmonth, selectedyear);		
			String enddate = df.format( new Date(time.toMillis(true)));

			repeatids = new ArrayList<String>();			
			ServerConnector.createEvent(new ServerConnectorListener<JsonObject>() {
				@Override
				public void requestFinished(JsonObject json) {					

					try {

						FileApi.writeJsonToStorage(json, "actualEvent", AddGroupActivity.this);
						Intent intent = new Intent(getBaseContext(), GroupDetailActivity.class);
						startActivity(intent);			
					} catch (IOException e) {
						Log.e(STORAGE_SERVICE, e.toString());
					}
				}

				@Override
				public void requestError(ServerError error) {
				}
			}, name, description, fachgebiet, building, begindate, enddate ,ltg.latitude, ltg.longitude );

			for (int i = 1; i < beginlist.size(); i++)
			{				
				begindate = beginlist.get(i);
				enddate = endlist.get(i);

				ServerConnector.createEvent(new ServerConnectorListener<JsonObject>() {
					@Override
					public void requestFinished(JsonObject json) {
						repeatids.add(json.get("id").toString());
					}

					@Override
					public void requestError(ServerError error) {
					}
				}, name, description, fachgebiet, building, begindate, enddate ,ltg.latitude, ltg.longitude );

			}
			Intent intent = new Intent(getBaseContext(), GroupDetailActivity.class);
	//		intent.putStringArrayListExtra("repeatevents", repeatids);
			startActivity(intent);			
	//		finish();
		}
		else
		{*/
			Log.i("DONE", "Done");
			// FIXME make minute duration properly
			
		//}

	}

	/**
	 * check if all necessary input is entered. then show save buttons
	 */
	private void checkInputFromUser(){
		BootstrapEditText textview = (BootstrapEditText) findViewById(R.id.vName);
		String name = textview.getText().toString();

		BootstrapEditText desc = (BootstrapEditText) findViewById(R.id.descText);
		String description = desc.getText().toString();

		if(interestsSet && starttimeset && endtimeset && dateset && !description.isEmpty() && !name.isEmpty() && locationset){
			transitionToSave();
		} else {
			transitionToCancel();
		}
	}


	public class InputFilterMinMax implements InputFilter {

		private int min, max;

		public InputFilterMinMax(int min, int max) {
			this.min = min;
			this.max = max;
		}

		public InputFilterMinMax(String min, String max) {
			this.min = Integer.parseInt(min);
			this.max = Integer.parseInt(max);
		}

		@Override
		public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
			try {
				int input = Integer.parseInt(dest.toString() + source.toString());
				if (isInRange(min, max, input))
					return null;
			} catch (NumberFormatException nfe) { }
			return "";
		}

		private boolean isInRange(int a, int b, int c) {
			return b > a ? c >= a && c <= b : c >= b && c <= a;
		}
	}

	public void startSetInterestActivity(View view){
		Intent interestIntent = new Intent(this, SetInterestActivity.class);
		interestIntent.putExtra(SetInterestActivity.MODE_SINGLE, true);
		startActivityForResult(interestIntent, SetInterestActivity.REQUEST_INTEREST);
	}

	/**
	 * Get interests from storage or server and initiate views
	 */
	private void setupInterests(){
		mInterestView = (LinearLayout) findViewById(R.id.interest_container);

		// load interest tree
		JsonValue interestJson;
		Log.i(TAG, "Try loading interests from storage...");
		if((interestJson = FileApi.readJsonFromStorage("interests", this)) != null){
			if(interestJson.isArray()){
				mInterestTree = new InterestTree(interestJson.asArray());
				createInterestViews();
			}
		} else {
			// get list from server
			Log.i(TAG, "No files in storage available, try loading interests from server...");
			ServerConnector.getInterests(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					if(json.isArray()){
						mUserInterests.clear();
						for (int i = 0; i < json.size(); i++) {
							try {
							mUserInterests.add(Integer.parseInt(
									json.asArray().get(i).asObject().get(Constants.JSON_INTEREST_ID).asString()));
							} catch (NullPointerException e){
								// skip
							} catch (UnsupportedOperationException e){
								// skip
							}
						}
					}

					mInterestTree = new InterestTree(json);
					// if the other one finished first, create interest text views
					if(mUserInterests != null){
						createInterestViews();
					}
				}
				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
					Toast.makeText(getBaseContext(), "Error loading filters", Toast.LENGTH_LONG).show();
				}
			});
		}
	}

	@SuppressLint("UseSparseArrays")
	private void createInterestViews(){
		Log.d(TAG, "Create interest views...");

		TextView interestText = (TextView) findViewById(R.id.interest);
		if(mUserInterests != null && mUserInterests.size() == 0){
			interestText.setText(R.string.interest_choose_single);
		} else if(mUserInterests != null && mUserInterests.size() == 1 && mUserInterests.get(0) != 0) {
			InterestNode node = mInterestTree.find(mUserInterests.get(0));
			if(node != null){
				interestText.setText(node.getInterestName());
			}
		} else if(mUserInterests != null && mUserInterests.size() == 2){
			InterestNode node1 = mInterestTree.find(mUserInterests.get(0));
			InterestNode node2 = mInterestTree.find(mUserInterests.get(1));

			String string = "";
			if(node1 != null && node1.getChildren().size() < 1){
				string += node2.getInterestName();
				string += " > ";
				string += node1.getInterestName();
			} else if(node2 != null && node2.getChildren().size() < 1){
				string += node1.getInterestName();
				string += " > ";
				string += node2.getInterestName();
			}
			interestText.setText(string);
		} else {
			interestText.setText(R.string.interest_choose_single);
		}
	}

	private void transitionToSave(){
		((TextView)findViewById(R.id.user_interaction_title)).setText(R.string.user_interaction_add_group_save);
		findViewById(R.id.user_interaction_save_changes).setVisibility(View.VISIBLE);
		findViewById(R.id.user_interaction_cancel).setVisibility(View.GONE);

		if(!mTransitionStateSave){
			((TransitionDrawable) findViewById(R.id.user_interaction)
					.getBackground()).startTransition(250);
		}

		mTransitionStateSave = true;
	}

	private void transitionToCancel(){
		((TextView)findViewById(R.id.user_interaction_title)).setText(R.string.user_interaction_add_group);
		findViewById(R.id.user_interaction_save_changes).setVisibility(View.GONE);
		findViewById(R.id.user_interaction_cancel).setVisibility(View.VISIBLE);

		if(mTransitionStateSave){
			((TransitionDrawable) findViewById(R.id.user_interaction)
					.getBackground()).reverseTransition(250);
		}

		mTransitionStateSave = false;
	}

	/**
	 * Show view with user interaction "save changes"
	 */
	private void showUserInteraction(){
		if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
			mUserInteractionView.setVisibility(View.VISIBLE);

			ValueAnimator mAnimator = slideAnimator(0, (int) getResources().getDimension(R.dimen.item_userinteraction));
			mAnimator.start();
		} else {
			mUserInteractionView.setVisibility(View.VISIBLE);
		}
	}

	/**
	 * hide view with user interaction "save changes"
	 */
	private void hideUserInteraction(){
		if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
			int finalHeight = mUserInteractionView.getHeight();

			ValueAnimator mAnimator = slideAnimator(finalHeight, 0);

			mAnimator.addListener(new Animator.AnimatorListener() {
				@Override
				public void onAnimationEnd(Animator animator) {
					mUserInteractionView.setVisibility(View.GONE);
				}

				@Override
				public void onAnimationCancel(Animator arg0) {}

				@Override
				public void onAnimationRepeat(Animator arg0) {}

				@Override
				public void onAnimationStart(Animator arg0) {}
			});
			mAnimator.start();
		} else {
			mUserInteractionView.setVisibility(View.GONE);
		}
	}

	private ValueAnimator slideAnimator(int start, int end) {

		ValueAnimator animator = ValueAnimator.ofInt(start, end);

		animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator valueAnimator) {
				//Update Height
				int value = (Integer) valueAnimator.getAnimatedValue();
				ViewGroup.LayoutParams layoutParams = mUserInteractionView.getLayoutParams();
				layoutParams.height = value;
				mUserInteractionView.setLayoutParams(layoutParams);
			}
		});
		return animator;
	}
	
}
